#include "Shell.h"

Shell::Shell() {
	cout << "shell" << endl;
	mailer = NULL;
	nodes.clear();
}
Shell::~Shell() {
	cout << "shell des'tor" << endl;
}

void Shell::go() {
	int userChoice = 0, id;
	string filename;

	do {
		this->printMenu();
		cin >> userChoice;
		getchar();

		cout << "userChoice is: " << userChoice << endl;

		if (false) {//)!mailer->getStabilize()){
			cout
					<< "cann't change settings until system is stable, please wait.."
					<< endl;
		} else {
			switch (userChoice) {
			case 1://createNet
				cout << "enter fileName" << endl;
				getline(cin, filename);
				cout << filename << endl;

				createNet(filename);
				waitForIT();
				break;

			case 2://printRT
				cout << "enter node number (1-" << this->nodes.size()
						<< ") x for all nodes" << endl;
				cin >> id;
				if (id == 0) {
					cout << "print all" << endl;
					for (map<int, Node*>::iterator i = nodes.begin(); i
							!= nodes.end(); i++) {
						if (i->second)
							this->printRT(i->second->getID());
					}
				} else
					this->printRT(id);
				break;
			case 3://killNode
				cout << "enter node number to kill: ";
				cin >> id;
				if (this->nodes[id] == 0)
					cout << "node does not exist!" << endl;
				else
					killNode(id);
				break;
			case 4://KillALl
				killAll();
				break;
			case 5:
				this->mailer->setStabilize(false);
				//run mailer by selected schedule alg.
				int alg;
				cout << "choose your way of life:" << endl;
				cout << this->mailer->RR << ":RoundRobin" << endl;
				cout << this->mailer->MLQ << ":MultiLevelQueue" << endl;
				cout << this->mailer->OUR << ":Use Sunscreen" << endl;
				cin >> alg;
				getchar();
				int quanta;
				cout << "quanta costa?" << endl;
				cin >> quanta;
				this->mailer->algQuanta = quanta;
				this->mailer->schedule = alg;
				this->mailer->start();
				//this->run(0,NULL);
				//				while (!this->mailer->getStabilize());
				waitForIT();
				break;
			case 6://sendMsg
				sendPacket();
				break;
			case 7://revive
				revive();
				break;
			}//switch
		}
		if (userChoice != 0) {
			waitForIT();
			//			while (get_sys_inbox_size())
			//				popMsg();
		}

	} while (userChoice != 0);
	if (!nodes.empty()) killAll();

}

void Shell::printMenu() {
	cout << endl << "Menu:" << endl;
	cout << "1: create net" << endl;
	if (!this->nodes.empty()) {
		cout << "2: printRT" << endl;
		cout << "3: KillNode" << endl;
		cout << "4: KillAllNodes" << endl;
		cout << "5: RUN!!!" << endl;
		cout << "6: send message" << endl;
		cout << "7: revive node " << endl;
	}
	cout << "0: exit" << endl;
}
void Shell::createNet(string filename) {
	ifstream input;
	string buff;
	int graphSize;
	input.open(filename.c_str());

	if (!input) {
		cerr << "error opening file: " << filename << endl;
		exit(1);
	}
	getline(input, buff);
	this->mailerBufferSize = atoi(buff.c_str());
	cout << "buffer size is: " << buff << "(" << this->mailerBufferSize << ")"
			<< endl;
	this->mailer = new Mailer(&nodes, mailerBufferSize, this);
	getline(input, buff);
	graphSize = atoi(buff.c_str());
	cout << "number of nodes in graph: " << graphSize << endl;

	while (!input.eof()) {

		getline(input, buff);
		if (!buff.empty()) {
			int nodeNum = atoi(&buff[0]);
			buff.erase(0, buff.find_first_of(" ") + 1);
			Node *n = new Node(nodeNum, buff, graphSize, mailer);
			cout << "node " << nodeNum << " created" << endl;
			this->nodes[nodeNum] = n;
			//            cout<<"nodes["<<nodeNum<<"] = "<<nodes[nodeNum]->getID()<<endl;
		}
	}
	input.close();
	cout << "network created..." << endl;
}
void Shell::killNode(int id) {
	//  nodes.at(id)->active = false;
	stringstream s;
	s << id;
	//	cout<<"killNode"<<endl;
	for (map<int, Node*>::iterator it = nodes.begin(); it != nodes.end(); it++) {
		if (it->second->active) {
			//			cout<<"in! first: "<<it->first<<" second : "<<it->second<<endl;
			Message* msg = new Message(s.str(), 0, it->first, Message::SYSTEM);
			//			cout<<"message created"<<endl;
			msg->kill = true;
			//			cout << "sending kill node for: " << it->first << endl;
			mailer->insertMsg(NULL, msg);
		}
	}
	mailer->setStabilize(false);
	while (!mailer->getStabilize())
		;
	//	cout << "system stable " << mailer->getStabilize() << " sys inbox size "
	//			<< sys_inbox.size() << " inbox size : " << inbox.size() << endl;
	while (get_sys_inbox_size()) {
		//		cout << "a" << endl;
		popMsg();
	}
	//	cout << "system stable " << mailer->getStabilize() << " sys inbox size "
	//			<< sys_inbox.size() << endl;

}
void Shell::revive() {
	int id;
	cout << "enter node number to revive: ";
	cin >> id;
	if (this->nodes[id]->active)
		cout << "node does exist!" << endl;
	else {
		stringstream s;
		s << id;
		Message* msg = new Message(s.str(), 0, id, Message::SYSTEM);
		msg->revive = true;
		mailer->insertMsg(NULL, msg);
		mailer->setStabilize(false);
		waitForIT();
		/*while (!this->mailer->getStabilize()) {
		 //				cout << "system stable " << mailer->getStabilize() << " sys inbox size "
		 //							<< sys_inbox.size() << " inbox size : " << inbox.size() << endl;
		 }
		 cout<<"a"<<endl;
		 while (this->sys_inbox.size()){
		 //			cout << "system stable " << mailer->getStabilize() << " sys inbox size "
		 //										<< sys_inbox.size() << " inbox size : " << inbox.size() << endl;
		 popMsg();
		 }*/
	}
}

void Shell::killAll() {
	cout << "killing all - sending exit msg to mailer:" << endl;
	for (map<int, Node*>::iterator it = nodes.begin(); it != nodes.end(); it++) {
		if (it->second) {
			cout << "killAll send kill to " << it->first << endl;
			it->second->active = false;
		}
	}
	cout<<"killing mailer"<<endl;
	if (mailer) mailer->active = false;

	if (!nodes.empty())
		for_each(nodes.begin(), nodes.end(), DeleteMapFntor<int, Node*> ());

	if (mailer){
		delete mailer;
	}
	this->nodes.clear();

}

void Shell::printRT(int id) {
	if (this->nodes[id] && this->nodes[id]->active)
		cout << this->nodes[id]->printRT();
	else
		cout << "no node with id \"" << id << "\" is in the system" << endl;
}
void Shell::sendPacket() {
	string message;
	int source, target;
	cout << "Enter source: ";
	cin >> source;
	getchar();
	cout << endl;
	cout << "Enter target: ";
	cin >> target;
	getchar();
	cout << endl;
	cout << "Enter message: ";
	getline(cin, message);
	cout << endl << endl;
	mailer->setStabilize(false);
	cout << "Sending Message" << endl;
	Message* Msg = new Message(message, source, target, Message::MSG);
	//cout<<"shell inputed:"<<Msg.toString()<<endl;
	mailer->insertMsg(this->nodes[source], Msg);

	while (!this->mailer->getStabilize()) {
	}

	while (!this->get_sys_inbox_size())
		popMsg();
}

void Shell::waitForIT() {
	while (!this->mailer->getStabilize()) {
	}

	while (this->get_sys_inbox_size())
		popMsg();
}
void Shell::run(int scheduleNum, void* args) {

}

void Shell::handleSysMsg(Message* msg) {
	//	cout<<"shell handle sys msg"<<endl;
	cout << msg->msg << endl;

	delete msg;

}
void Shell::handleRTMsg(Message* msg) {
	cout << "shell handle rt msg" << endl;
	delete msg;
}
void Shell::handleMsg(Message* msg) {
	cout << "shell handle regular msg" << endl;
	delete msg;
}

